//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<pyxeres_main.cpp>
///	@path	~/src/pyxeres/
///	@date	2008/11/04
///	@brief	.

#include "config/config.h"

#include <process.h>

#include "lib/system/thread_debug.h"

#include "database/xdata/CDirectoryData.h"
#include "database/xres/CLocalFileSystem.h"
#include "database/xres/CXmlFileHandler.h"

#include "python/py_boost_decl.h"
#include "python/python_plug.h"
#include "python/wrap/expose_python.h"

#include "engine/xcore/xeres_engine.h"

#include "pyxeres/expose/expose_py_engine.h"

#pragma comment(lib,"python25.lib")

using namespace xeres;

static bool s_bRun = false;
static HANDLE s_hThread = NULL;
static HANDLE s_hBeginEvent = NULL;
static function<void()> s_loopFn = NULL;

void active_loop( function<void()> fn )
{
	s_loopFn = fn;
	::SetEvent( s_hBeginEvent );
}

// xeres reg proc
void reg( void )
{
	Engine::instance().DataManager::Initialize();

	// Configuration file system.
	Ref<CLocalFileSystem> cwd_filesystem = new CLocalFileSystem;
	cwd_filesystem->SetPathBase( _S("/") );
	Ref<CDirectoryData> cwd_root = new CDirectoryData( cwd_filesystem , _S("/") , _S("/.") );

	// Add root directory to engine.
	Engine::instance().AddDataEntryRoot( cwd_root );

	// Create XML file handler.
	Ref<CXmlFileHandler> xml = new CXmlFileHandler;
	
	// Register file handler.
	cwd_filesystem->AddFileHandler( _S("xml") , xml );

	expose_basic_to_python();
	expose_database_to_python( &Engine::instance() );
 	expose_ui_to_python( NULL , NULL , &Engine::instance() );
 	expose_engine_to_python();
 	expose_app_to_python();
}

unsigned int __stdcall XeresMainThread( void * data )
{
	// Setup python interface.
	{
		Engine::instance();

		PyGILState_STATE gstate;
		gstate = PyGILState_Ensure();
		PythonPlug::instance().Initialize( NULL );
		PythonPlug::instance().RegisterModule( "xeres" , reg );
		PyGILState_Release(gstate);

		s_hBeginEvent = ::CreateEvent( NULL , FALSE , FALSE , NULL );
	}

	while( true )
	{
		::WaitForSingleObject( s_hBeginEvent , INFINITE );
		{
			if( !s_bRun )
				break;

			PyGILState_STATE gstate;
			gstate = PyGILState_Ensure();
			s_loopFn();
			PyGILState_Release(gstate);
		}
	}

	// Uninitialize states.
	{
		::CloseHandle( s_hBeginEvent );
		PyGILState_STATE gstate;
		gstate = PyGILState_Ensure();
		if( Engine::instance().DataManager::IsInitialized() )
			Engine::instance().DataManager::Finalize();
		if( PythonPlug::instance().IsInitialized() )
			PythonPlug::instance().Finalize();
		PyGILState_Release(gstate);
	}
	return 0;
}

BOOST_PYTHON_MODULE( xeres )
{
	s_hThread = (HANDLE) _beginthreadex( 0 , 0 , XeresMainThread , NULL , 0 , 0 );
}

BOOL __declspec(dllexport) __stdcall DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
{
	switch( fdwReason )
	{
	case DLL_PROCESS_ATTACH:
		{
			if( !PyEval_ThreadsInitialized() )
				PyEval_InitThreads();
			s_bRun = true;
		}
		break;
	case DLL_PROCESS_DETACH:
		{
			s_bRun = false;
			::SetEvent( s_hBeginEvent );
			::Sleep(0);
			::WaitForSingleObject( s_hThread , INFINITE );
		}
		break;
	}
	return TRUE;
}
